using System;
//using System.Net;
//using System.IO;
using System.Configuration;
using System.Collections.Specialized;
using OnlinePayments.PaymenTech;
using System.Data.SqlClient;
using System.Collections.Generic;


// The gateway is set up for IP address validation so a user name and password are not used.
namespace OnlinePayments
{
    /// <summary>
    /// Summary description for OrbitalGateway.
    /// </summary>
    internal class OrbitalGateway : PaymentProcessor
    {
        private string _merchantID;
        private Dictionary<char, char> _responseCodes = new Dictionary<char, char>();

        public OrbitalGateway(SqlConnection conn, char processorCode, int ownerID)
            : base(conn, processorCode, ownerID)
        {
            _merchantID = _configStrings["MerchantID"];

            if (_merchantID == null)
                throw new Exception("Missing data in the OrbitalGateway config section");

            _responseCodes.Add('1', 'A'); // Accepted
            _responseCodes.Add('0', 'D'); // Declined
            _responseCodes.Add('2', 'E'); // Errored
        }

        public override char Authorize(CustomerInfo customerInfo,
            Int32 transactionID,
            decimal amount,
            out string responseCode,
            out string responseText,
            out string AVSResult,
            out string CVV2Response,
            out string processorTransactionID,
            out string authCode
            )
        {
            processorTransactionID = null;
            return NewOrderMessage("A", customerInfo, transactionID, amount, out responseCode, out responseText, out AVSResult, out CVV2Response, out authCode, ref processorTransactionID);
        }

        public override char Deposit(CustomerInfo customerInfo,
            Int32 transactionID,
            decimal amount,
            out string responseCode,
            out string responseText,
            out string AVSResult,
            out string CVV2Response,
            out string processorTransactionID
            )
        {
            string authCode;
            processorTransactionID = null;
            return NewOrderMessage("AC", customerInfo, transactionID, amount, out responseCode, out responseText, out AVSResult, out CVV2Response, out authCode, ref processorTransactionID);
        }

        public override char DepositWithPriorAuth(CustomerInfo customerInfo,
            Int32 transactionID,
            decimal amount,
            string processorTransactionID,
            string authCode,
            out string responseCode,
            out string responseText
            )
        {
            MarkForCapture2Element markForCapture = new MarkForCapture2Element();

            markForCapture.merchantID = _merchantID;
            markForCapture.terminalID = "001";
            markForCapture.bin = "000001";
            markForCapture.orderID = transactionID.ToString();
            markForCapture.amount = (amount * 100).ToString("G0");
            markForCapture.txRefNum = processorTransactionID;

            try
            {
                PaymentechGatewayPortTypeClient gw = new PaymentechGatewayPortTypeClient();
                MarkForCaptureResponse2Element rsp = gw.MarkForCapture2(markForCapture);

                if (rsp.procStatus == "0")
                {
                    responseCode = rsp.respCode;
                    responseText = rsp.respCodeMessage;
                    processorTransactionID = rsp.txRefNum;
                    authCode = rsp.authorizationCode;

                    return _responseCodes[rsp.approvalStatus[0]];
                }
                else
                {
                    responseCode = "-2";
                    responseText = "Error submitting transaction : " + rsp.procStatus.ToString();
                    processorTransactionID = string.Empty;
                    authCode = string.Empty;

                    return 'E';
                }
            }
            catch (Exception err)
            {
                responseCode = "-3";
                responseText = "Exception submitting transaction : " + err.Message;
                processorTransactionID = string.Empty;
                authCode = string.Empty;

                return 'E';
            }
        }

        public override char Refund(
            CustomerInfo customerInfo,
            Int32 transactionID,
            decimal amount,
            string priorProcessTransactionID,
            out string responseCode,
            out string responseText,
            out string processorTransactionID
            )
        {
            string AVSResponse;
            string CVV2Response;
            string authCode;
            char result = NewOrderMessage("R", customerInfo, transactionID, amount, out responseCode, out responseText, out AVSResponse, out CVV2Response, out authCode, ref priorProcessTransactionID);
            processorTransactionID = priorProcessTransactionID;
            return result;
        }

        private char NewOrderMessage(
            string messageType,
            CustomerInfo customerInfo,
            Int32 transactionID,
            decimal amount,
            out string responseCode,
            out string responseText,
            out string AVSResult,
            out string CVV2Response,
            out string authCode,
            ref string processorTransactionID)
        {
            NewOrderRequestElement transaction = new NewOrderRequestElement();

            string customerName = customerInfo.FirstName + " " + customerInfo.LastName;
            transaction.ccAccountNum = customerInfo.CardNumber;
            transaction.merchantID = _merchantID;
            transaction.terminalID = "001";
            transaction.industryType = "EC";
            transaction.transType = messageType;
            transaction.bin = "000001";
            transaction.orderID = transactionID.ToString();
            transaction.customerRefNum = transactionID.ToString();
            transaction.profileOrderOverideInd = "OA";
            transaction.amount = (amount * 100).ToString("G0");
            if (messageType == "R")
                transaction.txRefNum = processorTransactionID;
            int iExpDate;
            // If the card expiration is not available or is past due then don't pass an expiration date.
            if (customerInfo.CardExpiration == null || customerInfo.CardExpiration == string.Empty
                || customerInfo.CardExpiration.Length != 4 || !int.TryParse(customerInfo.CardExpiration, out iExpDate))
                transaction.ccExp = "";
            else if (DateTime.Parse("20" + (iExpDate % 100).ToString().PadLeft(2, '0') + "-" + (iExpDate / 100).ToString().PadLeft(2, '0') + "-01") < DateTime.Today)
                transaction.ccExp = "";
            else
                transaction.ccExp = "20" + customerInfo.CardExpiration.Substring(2, 2) + customerInfo.CardExpiration.Substring(0, 2);
            transaction.avsName =
                customerName.Substring(0, Math.Min(30, customerName.Length)).Trim();
            if (customerInfo.Address != null)
                transaction.avsAddress1 = customerInfo.Address.Substring(0, Math.Min(30, customerInfo.Address.Length)).Trim();
            if (customerInfo.City != null)
                transaction.avsCity = customerInfo.City.Substring(0, Math.Min(20, customerInfo.City.Length)).Trim();
            if (customerInfo.State != null)
                transaction.avsState = customerInfo.State.Substring(0, Math.Min(2, customerInfo.State.Length)).Trim();
            if (customerInfo.Zip != null)
                transaction.avsZip = customerInfo.Zip.Substring(0, Math.Min(10, customerInfo.Zip.Length)).Trim();
            switch (customerInfo.Country.ToLower())
            {
                case "united states":
                    transaction.avsCountryCode = "US";
                    break;
                case "canada":
                    transaction.avsCountryCode = "CA";
                    break;
                default:
                    transaction.avsCountryCode = "";
                    break;
            }
            //transaction.TzCode = "705";
            //transaction.CurrencyCode = "840";
            //transaction.CurrencyExponent = "2";
            //transaction.TxDateTime = DateTime.Now.ToString("hhmmssMMddyyyy");
            if (customerInfo.CVV2 != null)
            {
                transaction.ccCardVerifyNum = customerInfo.CVV2.Substring(0, Math.Min(3, customerInfo.CVV2.Length)).Trim();
                transaction.ccCardVerifyPresenceInd = "1";
            }

            try
            {
                PaymentechGatewayPortTypeClient gw = new PaymentechGatewayPortTypeClient();
                NewOrderResponseElement rsp = gw.NewOrder(transaction);

                if (rsp.procStatus == "0")
                {
                    responseCode = rsp.respCode;
                    AVSResult = rsp.avsRespCode;
                    CVV2Response = rsp.cvvRespCode;
                    responseText = rsp.respCodeMessage;
                    processorTransactionID = rsp.txRefNum;
                    authCode = rsp.authorizationCode;

                    return _responseCodes[rsp.approvalStatus[0]];
                }
                else
                {
                    responseCode = "-2";
                    responseText = "Error submitting transaction : " + rsp.procStatus.ToString();
                    AVSResult = string.Empty;
                    CVV2Response = string.Empty;
                    processorTransactionID = string.Empty;
                    authCode = string.Empty;

                    return 'E';
                }
            }
            catch (Exception err)
            {
                responseCode = "-3";
                responseText = "Exception submitting transaction : " + err.Message;
                AVSResult = string.Empty;
                CVV2Response = string.Empty;
                processorTransactionID = string.Empty;
                authCode = string.Empty;

                return 'E';
            }
        }
    }
}
